package com.niodata.dp.mybatis;

import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
import io.github.lukehutch.fastclasspathscanner.matchprocessor.ImplementingClassMatchProcessor;
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;
import java.lang.reflect.Modifier;
import java.util.List;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class MybatisTypeHandlerRegistryBean  implements ApplicationListener<ContextRefreshedEvent> {

  @Autowired
  private SqlSessionFactory sqlSessionFactory;

  @Value(value = "${mybatis.typehandler.packages}")
  private String typeHandlerPackages;


  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
  }

  public void setTypeHandlerPackages(String typeHandlerPackages) {
    this.typeHandlerPackages = typeHandlerPackages;
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent contextStartedEvent) {
    String pkgs = typeHandlerPackages == null ? "com.niodata.dp.mybatis"
        : "com.niodata.dp.mybatis;" + typeHandlerPackages;
    TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
    try {
      String[] allPkgs = pkgs.split(";");
      for (String pkg : allPkgs) {
        pkg = pkg.trim();
        if (pkg.length() == 0) {
          continue;
        }
        FastClasspathScanner scanner = new FastClasspathScanner(pkg);
        scanner.matchClassesImplementing(
            DpMybatisTypeHandler.class,
            new ImplementingClassMatchProcessor() {
            @Override
            public void processMatch(Class implementingClass) {
            }
          });
        ScanResult result = scanner.scan();
        List<String> classes = result.getNamesOfClassesImplementing(DpMybatisTypeHandler.class);
        for (String clazz : classes) {
          Class classEntity = Class.forName(clazz);
          if (Modifier.isAbstract(classEntity.getModifiers())) {
            continue;
          }
          DpMybatisTypeHandler handler =
              (DpMybatisTypeHandler) (Class.forName(clazz).newInstance());
          registry.register(
              handler.getJavaClass(), handler.getJdbcType(), handler.getTypeHandlerClass());
        }
      }
    } catch (Exception exception) {
      //nothing to do
    }
  }
}
